package com.boot.config;


import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.provisioning.JdbcUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;

import javax.sql.DataSource;

@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {

        //接口路径授权配置
        http.authorizeHttpRequests(authorizeHttpRequests ->
                authorizeHttpRequests
                        //********************************角色****************************************
                        .requestMatchers("/admin/api").hasRole("admin") //必须有admin角色才能访问到
                        .requestMatchers("/user/api").hasAnyRole("admin", "user") // /user/api:admin、user都是可以访问

                        //********************************权限****************************************
                        .requestMatchers("/admin/api").hasAuthority("admin:api") //必须有admin:api权限才能访问到
                        .requestMatchers("/user/api").hasAnyAuthority("admin:api", "user:api") //有admin:api、user:api权限能访问到


                        //********************************匹配模式****************************************
                        .requestMatchers("/admin/api/?").hasAuthority("admin:api") //必须有admin:api权限才能访问到
                        .requestMatchers("/user/api/my/*").hasAuthority("admin:api") //必须有admin:api权限才能访问到

                        .requestMatchers("/admin/api/a/b/**").hasAuthority("admin:api") //必须有admin:api权限才能访问到

                        .requestMatchers("/app/api").permitAll() //任何人可以访问

                        .requestMatchers("/login").permitAll()
                        .anyRequest().authenticated()
        );

        //登录配置
        http.formLogin(formLogin ->
                formLogin
                        .loginProcessingUrl("/login")
                        .loginProcessingUrl("/login")
                        .defaultSuccessUrl("/index")
        );

        //关闭csrf
        http.csrf(AbstractHttpConfigurer::disable);


        //退出
        http.logout(logout -> logout.invalidateHttpSession(true));

        //借助异常处理配置一个未授权时跳转的错误页面
        http.exceptionHandling(e -> e.accessDeniedPage("/noAuth"));

        return http.build();


    }

    @Bean
    public UserDetailsService userDetailsService(DataSource dataSource) {
        JdbcUserDetailsManager userDetailsManager = new JdbcUserDetailsManager();
        userDetailsManager.setDataSource(dataSource);

        //admin用户具有admin、user角色
        UserDetails admin = User.withUsername("admin").password("123456").roles("admin", "user").build();
        UserDetails user = User.withUsername("user").password("123456").roles("user").build();
        UserDetails admin1 = User.withUsername("admin1").password("123456").authorities("admin:api", "user:api").build();
        UserDetails user1 = User.withUsername("user1").password("123456").authorities("user:api").build();

        if (!userDetailsManager.userExists("admin") && !userDetailsManager.userExists("user")) {
            userDetailsManager.createUser(admin);
            userDetailsManager.createUser(user);
            userDetailsManager.createUser(admin1);
            userDetailsManager.createUser(user1);
        }

        return userDetailsManager;
    }

    /**
     * 一个什么都不做的密码编码器
     */
    @Bean
    public PasswordEncoder passwordEncoder() {
        //明文加密
        return NoOpPasswordEncoder.getInstance();
    }

}
